

namespace Stee.CAP8.MessageBus.Sagas.Core.Sagas
{
    using Newtonsoft.Json;
    using Stee.CAP8.MessageBus.Interface.Models;
    using Stee.CAP8.MessageBus.Sagas.Core.Bus;
    using Stee.CAP8.MessageBus.Sagas.Core.Common;
    using Stee.CAP8.MessageBus.Sagas.Core.Sagas.SagaData;
    using Stee.CAP8.MessageBus.Sagas.Core.Sagas.Storages.Nodes;
    using Stee.CAP8.MessageBus.Sagas.Core.Sagas.Storages.Steps;
    using System;
    using System.Collections.Generic;
    using System.Runtime.CompilerServices;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;

   

    public abstract class BaseMainSaga<TSagaData>  where TSagaData: BaseSagaData
    {
        public ISagaStepStorage SagaStepStorage;
        private readonly ISagaNodeStorage sagaNodeStorage;

        private DateTime DeadTime;
        public int DeadlineSeconds = 4;
        /// <summary>
        /// 设置超时时间
        /// </summary>
        /// <returns></returns>
        public DateTime SetTimeOut() => DeadTime = DateTime.Now.AddSeconds(DeadlineSeconds);
        /// <summary>
        /// Saga是否超时
        /// </summary>
        /// <returns></returns>
        protected bool IsTimeOut() => DateTime.Now > DeadTime;


        protected TSagaData Data { get; private set; }
        public IBus Bus { get; set; }
        public BaseMainSaga(IBus bus,ISagaStepStorage sagaStepStorage,ISagaNodeStorage sagaNodeStorage)
        {
            this.Bus = bus;
            this.sagaNodeStorage = sagaNodeStorage;
            this.SagaStepStorage = sagaStepStorage;
        }

        private CommandMessage commandMessage;
        public void SendCommand() => this.Bus.SendCommand(this.commandMessage);
        public void SendCommand(string actionName, string topicName, string replyChannel, object instance)
        {
            this.commandMessage.Action = actionName;
            this.commandMessage.Source = topicName;
            this.commandMessage.ReplyChannel = replyChannel;
            this.commandMessage.Data = instance.ObjToBytes();
            this.commandMessage.RecordID = "";
            this.SendCommand();
        }
        public abstract Task HandleReply(CommandMessage message);

       
        
        public void SetSagaData(TSagaData sagaData) 
        {
            this.Data = sagaData;
        }


        public void SetParams(CommandMessage message,TSagaData sagaData) 
        {
            this.commandMessage = message;
            this.SetSagaData(sagaData);
            this.SetTimeOut();
        }

        public CommandMessage GetCommandMessage() => this.commandMessage;

        public  Task Rollback()
        {
            //回滚哪些node呢
            //只回滚已经做成功的
            Console.WriteLine($"进入回滚流程，是否因为超时{this.IsTimeOut()}");
            var toBeRolledBackNodes = this.sagaNodeStorage.FindBySagaId(this.Data.SagaId,Storages.Enums.SagaNodeState.SUCCESS);
            toBeRolledBackNodes?.ForEach(node =>
            {
                var commandmessage = node.CommandMessageData.ToObject<CommandMessage>();
                this.Bus.SendCommand(commandmessage);
            });
            return Task.CompletedTask;
        }

        public async Task<string> WaitSagaFinish()
        {
            
            return await Task.Run( async() => {
                if (this.IsTimeOut())
                {
                    this.Rollback();
                    return this.GetCommandMessage().CorrelationID;

                }
                if (this.Data.IsDone())
                {
                    return this.GetCommandMessage().CorrelationID;
                }
                Thread.Sleep(400);
                return await this.WaitSagaFinish();

            }).ConfigureAwait(false);
            
        }
    }
    
}
